package com.vicki.music;

import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import android.app.Activity;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.ServiceConnection;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.provider.MediaStore;
import android.util.Log;

import com.vicki.music.MediaSqlite.MSQLiteOpenHelper;

public class MediaUtils {

	public static String MediaUtilsTag = "MediaUtils";

	public static final String Data_Artists = "artist";
	public static final String Data_Playlists = "playlist";
	public static final String Data_Albums = "album";
	public static final String Data_Songs = "songs";

	public String Data_TYPE = Data_Songs;
	public static final String DEFAULT_PLAYLIST = "default_playlist";
	private static IMediaPlaybackService sService;

	private static final Uri sArtworkUri = Uri
			.parse("content://media/external/audio/albumart");
	private static final BitmapFactory.Options sBitmapOptions = new BitmapFactory.Options();
	private static Bitmap mCachedBit = null;

	// sConnectionMap contains all binded MediaPlaybackService
	private static HashMap<Context, ServiceBinder> sConnectionMap = new HashMap<Context, ServiceBinder>();

	// all medias which will be binded with MediaAdapter
	private static ArrayList<MediaInfo> medias = new ArrayList<MediaInfo>();

	private static MediaUtils mediaUtils;

	public static MediaUtils getInstense() {
		if (mediaUtils == null) {
			mediaUtils = new MediaUtils();
		}
		return mediaUtils;
	}

	public static class ServiceToken {
		ContextWrapper mWrappedContext;

		ServiceToken(ContextWrapper context) {
			mWrappedContext = context;
		}
	}

	public static ServiceToken bindToService(Activity context,
			ServiceConnection callback) {
		Activity realActivity = context.getParent();
		if (realActivity == null) {
			realActivity = context;
		}
		ContextWrapper cw = new ContextWrapper(realActivity);
		ServiceBinder sb = new ServiceBinder(callback);
		if (cw.bindService((new Intent()).setClass(cw,
				MediaPlaybackService.class), sb, Context.BIND_AUTO_CREATE)) {
			sConnectionMap.put(cw, sb);
			Log.i("test", "sConnectionMap size is " + sConnectionMap.size());
			return new ServiceToken(cw);
		}
		Log.e("Music", "Failed to bind to service");
		return null;
	}

	public static void unbindFromService(ServiceToken token) {
		if (token == null) {
			Log.e("MusicUtils", "Trying to unbind with null token");
			return;
		}
		ContextWrapper cw = token.mWrappedContext;
		ServiceBinder sb = sConnectionMap.remove(cw);
		if (sb == null) {
			Log.e("MusicUtils", "Trying to unbind for unknown Context");
			return;
		}
		cw.unbindService(sb);
		if (sConnectionMap.isEmpty()) {
			// presumably there is nobody interested in the service at this
			// point,
			// so don't hang on to the ServiceConnection
			sService = null;
		}
		Log.i("test", "sConnectionMap size is " + sConnectionMap.size());
	}

	private static class ServiceBinder implements ServiceConnection {

		ServiceConnection mCallback;

		ServiceBinder(ServiceConnection callback) {
			mCallback = callback;
		}

		public void onServiceConnected(ComponentName className,
				android.os.IBinder service) {
			sService = IMediaPlaybackService.Stub.asInterface(service);
			if (mCallback != null) {
				mCallback.onServiceConnected(className, service);
			}
		}

		public void onServiceDisconnected(ComponentName className) {
			if (mCallback != null) {
				mCallback.onServiceDisconnected(className);
			}
			sService = null;
		}
	}

	public void play() {

		try {
			sService.play();
		} catch (RemoteException e) {
			e.printStackTrace();
		}

	}

	public void next() {
		try {
			sService.next();
		} catch (RemoteException e) {
			e.printStackTrace();
		}
	}

	public void prev() {
		try {
			sService.prev();
		} catch (RemoteException e) {
			e.printStackTrace();
		}
	}

	public long duration() {
		if (sService != null) {
			try {
				return sService.duration();
			} catch (RemoteException ex) {
			}
		}
		return -1;
	}

	public static void scanSdCard(Context context, int cmd) {
		Intent intent = new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri
				.parse("file://"
						+ Environment.getExternalStorageDirectory()
								.getAbsolutePath()));
		intent.putExtra("cmd", cmd);
		context.sendBroadcast(intent);
	}

	public void bind_data_adapter(Context context, String tabId) {
		if (context == null || tabId == null) {
			return;
		}
		List<String> father = null;
		List<MediaInfo> child = null;
		ContentResolver resolver = context.getContentResolver();
		if (Data_Artists.equals(tabId)) {
			father = find_father_data(resolver, new String[] { tabId });
			Log.i(MediaUtilsTag, "father:" + father.size());
			ExpandAdapter expandAdapter = (ExpandAdapter) MediaTabActivity.exp_list_adapter;
			expandAdapter.onDatasetChanged(father, child);
			return;
		} else if (Data_Playlists.equals(tabId)) {
			MediaSqlite mediaSqlite = new MediaSqlite(context);
			father = mediaSqlite
					.query(new String[] { MSQLiteOpenHelper.PLAYLIST });
		} else if (Data_Songs.equals(tabId)) {
			father = find_father_data(resolver,
					new String[] { MediaStore.Video.Media.TITLE });
		} else {
			father = find_father_data(resolver, new String[] { tabId });
		}
		MediaAdapter mediaAdapter = (MediaAdapter) MediaTabActivity.displayAdapter;
		mediaAdapter.onDatasetChanged(father, null);
	}

	public List<MediaInfo> find_child_data(ContentResolver resolver,
			String where, String[] values) {
		ArrayList<MediaInfo> childs = new ArrayList<MediaInfo>();
		Cursor cursor = resolver.query(
				MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
				MediaSqlite.MEDIA_ARGS, where + "=?", values, null);
		if (cursor == null)
			return null;
		cursor.moveToFirst();
		final int count = cursor.getCount();
		for (int i = 0; i < count; i++) {
			MediaInfo child = new MediaInfo(cursor.getString(0), cursor
					.getString(4), cursor.getString(5), "default_playlist",
					cursor.getString(1), cursor.getString(2), cursor
							.getString(3));
			childs.add(child);
			cursor.moveToNext();
		}
		return childs;
	}

	public List<String> find_father_data(ContentResolver resolver, String[] type) {
		ArrayList<String> fathers = new ArrayList<String>();
		Cursor cursor = resolver.query(
				MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, type, null, null,
				null);
		if (cursor == null)
			return null;
		cursor.moveToFirst();
		final int count = cursor.getCount();
		for (int i = 0; i < count; i++) {
			String father = cursor.getString(0);
			fathers.add(father);
			cursor.moveToNext();
		}
		unduplicate(fathers);
		return fathers;
	}

	public List<String> find_playlist(Context context) {
		MediaSqlite mediaSqlite = new MediaSqlite(context);
		mediaSqlite.queryAll();
		return null;
	}

	public static Bitmap getArtwork(Context context, long song_id,
			long album_id, boolean allowdefault) {
		if (album_id < 0) {
			// This is something that is not in the database, so get the album
			// art directly
			// from the file.
			if (song_id >= 0) {
				Bitmap bm = getArtworkFromFile(context, song_id, -1);
				if (bm != null) {
					return bm;
				}
			}
			if (allowdefault) {
				return getDefaultArtwork(context);
			}
			return null;
		}
		ContentResolver res = context.getContentResolver();
		Uri uri = ContentUris.withAppendedId(sArtworkUri, album_id);
		if (uri != null) {
			InputStream in = null;
			try {
				in = res.openInputStream(uri);
				return BitmapFactory.decodeStream(in, null, sBitmapOptions);
			} catch (FileNotFoundException ex) {
				// The album art thumbnail does not actually exist. Maybe the
				// user deleted it, or
				// maybe it never existed to begin with.
				Bitmap bm = getArtworkFromFile(context, song_id, album_id);
				if (bm != null) {
					if (bm.getConfig() == null) {
						bm = bm.copy(Bitmap.Config.RGB_565, false);
						if (bm == null && allowdefault) {
							return getDefaultArtwork(context);
						}
					}
				} else if (allowdefault) {
					bm = getDefaultArtwork(context);
				}
				return bm;
			} finally {
				try {
					if (in != null) {
						in.close();
					}
				} catch (IOException ex) {
				}
			}
		}

		return null;
	}

	private static Bitmap getArtworkFromFile(Context context, long songid,
			long albumid) {
		Bitmap bm = null;
		if (albumid < 0 && songid < 0) {
			throw new IllegalArgumentException(
					"Must specify an album or a song id");
		}
		try {
			if (albumid < 0) {
				Uri uri = Uri.parse("content://media/external/audio/media/"
						+ songid + "/albumart");
				ParcelFileDescriptor pfd = context.getContentResolver()
						.openFileDescriptor(uri, "r");
				if (pfd != null) {
					FileDescriptor fd = pfd.getFileDescriptor();
					bm = BitmapFactory.decodeFileDescriptor(fd);
				}
			} else {
				Uri uri = ContentUris.withAppendedId(sArtworkUri, albumid);
				ParcelFileDescriptor pfd = context.getContentResolver()
						.openFileDescriptor(uri, "r");
				if (pfd != null) {
					FileDescriptor fd = pfd.getFileDescriptor();
					bm = BitmapFactory.decodeFileDescriptor(fd);
				}
			}
		} catch (FileNotFoundException ex) {

		}
		if (bm != null) {
			mCachedBit = bm;
		}
		return bm;
	}

	private static Bitmap getDefaultArtwork(Context context) {
		BitmapFactory.Options opts = new BitmapFactory.Options();
		opts.inPreferredConfig = Bitmap.Config.RGB_565;
		return BitmapFactory.decodeStream(context.getResources()
				.openRawResource(R.drawable.icon), null, opts);
	}

	public void setShuffleMode() {

		if (sService == null) {
			Log.i(MediaUtilsTag, "sService is dead");
			return;
		}

		try {
			sService.setShuffleMode();
		} catch (RemoteException e) {
			e.printStackTrace();
		}
	}

	public void setRepeatMode() {
		if (sService == null) {
			Log.i(MediaUtilsTag, "sService is dead");
			return;
		}
		try {
			sService.setRepeatMode();
		} catch (RemoteException e) {
			e.printStackTrace();
		}
	}

	public int getRepeatMode() {
		if (sService == null) {
			Log.i(MediaUtilsTag, "sService is dead");
			return -1;
		}
		int repeat_mode = 0;
		try {
			repeat_mode = sService.getRepeatMode();
		} catch (RemoteException e) {
			e.printStackTrace();
		}
		return repeat_mode;
	}

	public int getShuffleMode() {
		if (sService == null) {
			Log.i(MediaUtilsTag, "sService is dead");
			return -1;
		}
		int shuffle_mode = 0;
		try {
			shuffle_mode = sService.getShuffleMode();
		} catch (RemoteException e) {
			e.printStackTrace();
		}
		return shuffle_mode;
	}

	public static class MediaInfo {

		public MediaInfo(String _title, String _path, String _album,
				String _playlist, String _duration, String _artist,
				String _display_name) {
			this._title = _title;
			this._path = _path;
			this._album = _album;
			this._playlist = _playlist;
			this._artist = _artist;
			this._duration = _duration;
			this._display_name = _display_name;
		}

		public MediaInfo() {

		}

		public String _title; // media title
		public String _path; // media path
		public String _album; // media album
		public String _playlist; // media path
		public String _duration; // media duration
		public String _artist; // media artist
		public String _display_name;

		public void set_album(String album) {
			_album = album;
		}

		public void set_playlist(String playlist) {
			_playlist = playlist;
		}

		public void set_artist(String artist) {
			_artist = artist;
		}
	}

	public static void unduplicate(List<String> list) {

		Log.i(MediaUtilsTag, "unduplicate " + list.size());

		for (int i = 0; i < list.size(); i++) {
			for (int y = i + 1; y < list.size(); y++) {
				if (list.get(i).equals(list.get(y))) {
					list.remove(y);
					y--;
				}
			}
		}
	}
}
